package cn.com.zj.zjwfprinter;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zj.usbsdk.UsbController;
import com.zj.wfsdk.WifiCommunication;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import cn.com.zj.command.sdk.Command;
import cn.com.zj.command.sdk.PrintPicture;
import cn.com.zj.command.sdk.PrinterCommand;
import io.dcloud.feature.uniapp.annotation.UniJSMethod;
import io.dcloud.feature.uniapp.bridge.UniJSCallback;
import io.dcloud.feature.uniapp.common.UniModule;

public class DragPrint extends UniModule {

    private static final String TAG = "TestWifiPrint";
    /******************************************************************************************************/
    final String[] items = {"复位打印机", "打印并走纸", "标准ASCII字体", "压缩ASCII字体", "取消倍高倍宽",
            "倍高倍宽", "取消加粗模式", "选择加粗模式", "取消倒置打印", "选择倒置打印", "取消黑白反显", "选择黑白反显",
            "取消顺时针旋转90°", "选择顺时针旋转90°", "走纸到切刀位置并切纸", "蜂鸣指令", "标准钱箱指令",
            "实时弹钱箱指令", "进入字符模式", "进入中文模式", "打印自检页", "禁止按键", "取消禁止按键",
            "设置汉字字符下划线", "取消汉字字符下划线", "进入十六进制模式"};
    final String[] itemsen = {"Print Init", "Print and Paper", "Standard ASCII font", "Compressed ASCII font", "Normal size",
            "Double high power wide", "Twice as high power wide", "Three times the high-powered wide", "Off emphasized mode", "Choose bold mode", "Cancel inverted Print", "Invert selection Print", "Cancel black and white reverse display", "Choose black and white reverse display",
            "Cancel rotated clockwise 90 °", "Select the clockwise rotation of 90 °", "Feed paper Cut", "Beep", "Standard CashBox",
            "Open CashBox", "Char Mode", "Chinese Mode", "Print SelfTest", "DisEnable Button", "Enable Button",
            "Set Underline", "Cancel Underline", "Hex Mode"};
    final byte[][] byteCommands = {
            {0x1b, 0x40, 0x0a},// 复位打印机
            {0x0a}, //打印并走纸
            {0x1b, 0x4d, 0x00},// 标准ASCII字体
            {0x1b, 0x4d, 0x01},// 压缩ASCII字体
            {0x1d, 0x21, 0x00},// 字体不放大
            {0x1d, 0x21, 0x11},// 宽高加倍
            {0x1b, 0x45, 0x00},// 取消加粗模式
            {0x1b, 0x45, 0x01},// 选择加粗模式
            {0x1b, 0x7b, 0x00},// 取消倒置打印
            {0x1b, 0x7b, 0x01},// 选择倒置打印
            {0x1d, 0x42, 0x00},// 取消黑白反显
            {0x1d, 0x42, 0x01},// 选择黑白反显
            {0x1b, 0x56, 0x00},// 取消顺时针旋转90°
            {0x1b, 0x56, 0x01},// 选择顺时针旋转90°
            {0x0a, 0x1d, 0x56, 0x42, 0x01, 0x0a},//切刀指令
            {0x1b, 0x42, 0x03, 0x03},//蜂鸣指令
            {0x1b, 0x70, 0x00, 0x50, 0x50},//钱箱指令
            {0x10, 0x14, 0x00, 0x05, 0x05},//实时弹钱箱指令
            {0x1c, 0x2e},// 进入字符模式
            {0x1c, 0x26}, //进入中文模式
            {0x1f, 0x11, 0x04}, //打印自检页
            {0x1b, 0x63, 0x35, 0x01}, //禁止按键
            {0x1b, 0x63, 0x35, 0x00}, //取消禁止按键
            {0x1b, 0x2d, 0x02, 0x1c, 0x2d, 0x02}, //设置下划线
            {0x1b, 0x2d, 0x00, 0x1c, 0x2d, 0x00}, //取消下划线
            {0x1f, 0x11, 0x03}, //打印机进入16进制模式
    };
/******************************************************************************************************/
    /***************************条                          码***************************************************************/
    final String[] codebar = {"UPC_A", "UPC_E", "JAN13(EAN13)", "JAN8(EAN8)",
            "CODE39", "ITF", "CODABAR", "CODE93", "CODE128", "QR Code"};
    final byte[][] byteCodebar = {
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
            {0x1b, 0x40},// 复位打印机
    };
    /******************************************************************************************************/
    private int connFlag = 0;
    private static boolean is58mm = true;//是否58mm
    private static int lang = 0;//0 简体 1BIG5 2 泰语 3韩语
    private boolean isConnected = false;
    private WifiCommunication wfComm = null;
    private int[][] u_infor;
    static UsbController usbCtrl = null;
    static UsbDevice dev = null;
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Log.e(TAG, "handleMessage: " + msg.what);
            if (msg.what == WifiCommunication.WFPRINTER_CONNECTED) {
                connFlag = 0;
                isConnected = true;
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "Connect successful");
                params.put("code", 1);
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                Log.e(TAG, "WFPRINTER_CONNECTED:");
            } else if (msg.what == WifiCommunication.WFPRINTER_DISCONNECTED) {
                isConnected = false;
                connFlag = 0;
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "Disconnect the  successful");
                params.put("code", -1);
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                Log.e(TAG, "WFPRINTER_DISCONNECTED:");
            } else if (msg.what == WifiCommunication.SEND_FAILED) {
                connFlag = 0;
                isConnected = false;
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "Send Data Failed,please reconnect");
                params.put("code", -1);
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
            } else if (msg.what == WifiCommunication.WFPRINTER_CONNECTEDERR) {
                connFlag = 0;
                isConnected = false;
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "Connect error");
                params.put("code", -1);
                Log.e(TAG, "WFPRINTER_CONNECTEDERR:");
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
            } else if (msg.what == WifiCommunication.WFPRINTER_REVMSG) {
                byte revData = (byte) Integer.parseInt(msg.obj.toString());
                if (((revData >> 6) & 0x01) == 0x01) {
                    Map<String, Object> params = new HashMap<>();
                    params.put("msg", "The printer has no paper");
                    params.put("code", -1);
                    mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                    Log.e(TAG, "WFPRINTER_REVMSG:");
                }
            }
        }
    };


    //连接网口打印机
    @UniJSMethod(uiThread = false)
    public void initSocket(JSONObject options, UniJSCallback callback) {
        try {
            try {
                if (wfComm != null) {
                    wfComm.close();
                    wfComm = null;
                    Log.d(TAG, "initSocket: wfCOM");
                }
            } catch (Exception e) {
            }

            wfComm = new WifiCommunication(mHandler);
            String strAddressIp = options.getString("ip");
            Log.d(TAG, "initSocket: " + strAddressIp);
            wfComm.initSocket(strAddressIp, 9100);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invokeAndKeepAlive(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "initSocket: " + e);
        }

    }

    //设置纸张宽度
    @UniJSMethod(uiThread = false)
    public void setPaperSize(JSONObject options, UniJSCallback callback) {
        try {
            is58mm = options.getBoolean("is58mm");
            Log.d(TAG, "setPaperSize: " + is58mm);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "setPaperSize: " + e);
        }

    }

    //设置纸张宽度
    @UniJSMethod(uiThread = false)
    public void setLang(JSONObject options, UniJSCallback callback) {
        try {
            lang = options.getIntValue("lang");
            Log.d(TAG, "setLang: " + lang);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "setPaperSize: " + e);
        }

    }


    //  打印测试页
    @UniJSMethod(uiThread = false)
    public void printBase64Test(JSONObject options, UniJSCallback callback) {
        try {
            String msg = options.getString("msg");
            SendDataString(new String(Base64.decode(msg, Base64.DEFAULT), StandardCharsets.UTF_8));
            SendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            SendDataByte(Command.GS_V_m_n);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "printTest: " + e);
        }

    }

    //  打印测试页
    @UniJSMethod(uiThread = false)
    public void printTest(JSONObject options, UniJSCallback callback) {
        try {
            String msg = options.getString("msg");
            SendDataString(msg);
            SendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            SendDataByte(Command.GS_V_m_n);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "printTest: " + e);
        }

    }

    //打印自定义小票
    @UniJSMethod(uiThread = false)
    public void myPrint(JSONObject options, UniJSCallback callback) {
        try {
            if (!isConnected) {
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "请先链接打印机");
                params.put("code", -1);
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                return;
            }
            JSONArray arrays = options.getJSONArray("data");
            Log.d(TAG, "myPrint: myPrint" + arrays.size());
            for (Object obj : arrays) {
                JSONObject object = (JSONObject) obj;
                String text = object.getString("text");
                int type = object.getIntValue("type");
                int align = object.getIntValue("align");
                int fontSize = object.getIntValue("fontSize");
                float imageScale = 1;
                if (object.containsKey("imageScale")) {
                    imageScale = object.getFloat("imageScale");
                }
                Log.d(TAG, "myPrint: 收到类型" + type);
                if (type == 0) {
                    Command.ESC_Align[2] = (byte) align;
                    SendDataByte(Command.ESC_Align);
                    Command.GS_ExclamationMark[2] = (byte) (fontSize & 0xff);
                    SendDataByte(Command.GS_ExclamationMark);
                    SendDataByte(text.getBytes("GBK"));
                } else {
                    final Bitmap mBitmap = base64ToBitmap(text);
                    Log.d(TAG, "myPrint: " + mBitmap);
                    byte[] buffer = PrinterCommand.POS_Set_PrtInit();
                    Command.ESC_Align[2] = (byte) align;
                    byte[] data = PrintPicture.POS_PrintBMP(mBitmap, (int) (is58mm ? 384 * imageScale : 576 * imageScale), 0);
                    wfComm.sndByte(buffer);
                    SendDataByte(Command.ESC_Align);
                    wfComm.sndByte(data);
                    wfComm.sndByte(new byte[]{0x0a});
                }


            }
            SendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            SendDataByte(Command.GS_V_m_n);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            Log.d(TAG, "myPrint: " + e);
        }
    }

    public Bitmap base64ToBitmap(String base64Str) {
        // 解码Base64编码的字符串
        byte[] decodedBytes = Base64.decode(base64Str, Base64.DEFAULT);

        // 将字节数组转换为Bitmap对象
        return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
    }


    // 关闭打印机
    @UniJSMethod(uiThread = false)
    public void close(JSONObject options, UniJSCallback callback) {
        try {
            isConnected = false;
            wfComm.close();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "close: " + e);
        }

    }

    /************************************************************************************************/
    private void SendDataByte(byte[] data) {
        wfComm.sndByte(data);
    }

    private void SendDataString(String data) {
        if (!TextUtils.isEmpty(data)) {
            Log.d(TAG, "SendDataString: wifi "+lang);
            if (lang == 0) {
                SendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                wfComm.sendMsg(data, "GBK");
            } else if (lang == 1) {
                SendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                wfComm.sendMsg(data, "BIG5");
            } else if (lang == 2) {
                SendDataByte(new byte[]{0x1c, 0x2e, 0x1b, 0x74, (byte) 0xff});
                wfComm.sendMsg(data, "CP874");
            } else if (lang == 3) {
                SendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                wfComm.sendMsg(data, "EUC-KR");
            }
        }

    }
/************************************************************************************************/
    /****************************************************************************************************/
    private void USBSendDataByte(byte[] data) {
        if (data.length > 0)
            usbCtrl.sendByte(data, dev);
    }

    private void USBSendDataString(String data) {
        Log.d(TAG, "USBSendDataString:  语言"+lang);
        if (!TextUtils.isEmpty(data)) {
            if (lang == 0) {
                USBSendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                usbCtrl.sendMsg(data, "GBK",dev);
            } else if (lang == 1) {
                USBSendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                usbCtrl.sendMsg(data, "BIG5",dev);
            } else if (lang == 2) {
                USBSendDataByte(new byte[]{0x1c, 0x2e, 0x1b, 0x74, (byte) 0xff});
                usbCtrl.sendMsg(data, "CP874",dev);
            } else if (lang == 3) {
                USBSendDataByte(new byte[]{0x1c, 0x26, 0x1b, 0x74, (byte) 0x00});
                usbCtrl.sendMsg(data, "EUC-KR",dev);
            }
        }


    }

    //
    private void USBSendDataBig5(String data) {

        if (data.length() > 0) {
            usbCtrl.sendMsg(data, "BIG5", dev);
        }
    }

    private void USBSendDataThai(String data) {

        if (data.length() > 0) {
            usbCtrl.sendMsg(data, "CP874", dev);
        }
    }

    private void USBSendDataKor(String data) {

        if (data.length() > 0) {
            usbCtrl.sendMsg(data, "EUC-KR", dev);
        }
    }

    /****************************************************************************************************/

//USB START
    @UniJSMethod(uiThread = false)
    public void connectUSBPrint(JSONObject options, UniJSCallback callback) {
        try {
            try {
                isConnected = false;
                if (usbCtrl != null) {
                    usbCtrl.close();
                    usbCtrl = null;
                    Log.d(TAG, "connectUSBPrint: closeUsb");
                }
            } catch (Exception e) {
            }

            usbCtrl = new UsbController((Activity) mUniSDKInstance.getContext(), mHandler);
            u_infor = new int[8][2];
            u_infor[0][0] = 0x1CBE;
            u_infor[0][1] = 0x0003;
            u_infor[1][0] = 0x1CB0;
            u_infor[1][1] = 0x0003;
            u_infor[2][0] = 0x0483;
            u_infor[2][1] = 0x5740;
            u_infor[3][0] = 0x0493;
            u_infor[3][1] = 0x8760;
            u_infor[4][0] = 0x0416;
            u_infor[4][1] = 0x5011;
            u_infor[5][0] = 0x0416;
            u_infor[5][1] = 0xAABB;
            u_infor[6][0] = 0x1659;
            u_infor[6][1] = 0x8965;
            u_infor[7][0] = 0x0483;
            u_infor[7][1] = 0x5741;
            usbCtrl.close();
            int i = 0;
            for (i = 0; i < 8; i++) {
                dev = usbCtrl.getDev(u_infor[i][0], u_infor[i][1]);
                if (dev != null)
                    break;
            }
            JSONObject jsonObject = new JSONObject();
            if (dev != null) {
                if (!(usbCtrl.isHasPermission(dev))) {
                    //Log.d("usb调试","请求USB设备权限.");
                    usbCtrl.getPermission(dev);
                } else {
                    Map<String, Object> params = new HashMap<>();
                    params.put("msg", "Connect successful");
                    params.put("code", 1);
                    mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                    isConnected = true;
                }
                jsonObject.put("code", 1);
            } else {
                jsonObject.put("code", -1);
            }


            callback.invokeAndKeepAlive(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "initSocket: " + e);
        }

    }


    //  打印测试页
    @UniJSMethod(uiThread = false)
    public void USBPrintBase64Test(JSONObject options, UniJSCallback callback) {
        try {
            String msg = options.getString("msg");
            USBSendDataString(new String(Base64.decode(msg, Base64.DEFAULT), StandardCharsets.UTF_8));
            USBSendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            USBSendDataByte(Command.GS_V_m_n);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "printTest: " + e);
        }

    }

    //  打印测试页
    @UniJSMethod(uiThread = false)
    public void USBPrintTest(JSONObject options, UniJSCallback callback) {
        try {
            String msg = options.getString("msg");
            USBSendDataString(msg);
            USBSendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            USBSendDataByte(Command.GS_V_m_n);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "printTest: " + e);
        }

    }

    //打印自定义小票
    @UniJSMethod(uiThread = false)
    public void myUSBPrint(JSONObject options, UniJSCallback callback) {
        try {
            if (!isConnected) {
                Map<String, Object> params = new HashMap<>();
                params.put("msg", "请先链接打印机");
                params.put("code", -1);
                mUniSDKInstance.fireGlobalEventCallback("PrintEvent", params);
                return;
            }
            JSONArray arrays = options.getJSONArray("data");
            Log.d(TAG, "USBPrint" + arrays.size());
            for (Object obj : arrays) {
                JSONObject object = (JSONObject) obj;
                String text = object.getString("text");
                int type = object.getIntValue("type");
                int align = object.getIntValue("align");
                int fontSize = object.getIntValue("fontSize");
                float imageScale = 1;
                if (object.containsKey("imageScale")) {
                    imageScale = object.getFloat("imageScale");
                }
                Log.d(TAG, "myPrint: 收到类型" + type);
                if (type == 0) {
                    Command.ESC_Align[2] = (byte) align;
                    USBSendDataByte(Command.ESC_Align);
                    Command.GS_ExclamationMark[2] = (byte) (fontSize & 0xff);
                    USBSendDataByte(Command.GS_ExclamationMark);
                    USBSendDataByte(text.getBytes("GBK"));
                } else {
                    final Bitmap mBitmap = base64ToBitmap(text);
                    Log.d(TAG, "myPrint: " + mBitmap);
                    byte[] buffer = PrinterCommand.POS_Set_PrtInit();
                    Command.ESC_Align[2] = (byte) align;
                    byte[] data = PrintPicture.POS_PrintBMP(mBitmap, (int) (is58mm ? 384 * imageScale : 576 * imageScale), 0);
                    usbCtrl.sendByte(buffer, dev);
                    usbCtrl.sendByte(buffer, dev);
                    USBSendDataByte(Command.ESC_Align);
                    usbCtrl.sendByte(data, dev);
                    usbCtrl.sendByte(new byte[]{0x0a}, dev);
                }


            }
            USBSendDataByte(PrinterCommand.POS_Set_PrtAndFeedPaper(48));
            USBSendDataByte(Command.GS_V_m_n);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            Log.d(TAG, "myPrint: " + e);
        }
    }

    // 关闭打印机
    @UniJSMethod(uiThread = false)
    public void closeUSB(JSONObject options, UniJSCallback callback) {
        try {
            isConnected = false;
            usbCtrl.close();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("code", 1);
            callback.invoke(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, "close: " + e);
        }

    }
//USB END

}
